package org.crystalrange.documents.web;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.apache.xmlbeans.impl.jam.mutable.MSourcePosition;
import org.aspectj.bridge.MessageWriter;
import org.crystalrange.documents.model.DocumentReference;
import org.crystalrange.documents.model.DocumentVersion;
import org.crystalrange.documents.model.DocumentVersionFile;
import org.crystalrange.model.User;
import org.crystalrange.service.UserService;
import org.springframework.security.core.context.SecurityContextHolder;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zkplus.databind.AnnotateDataBinder;
import org.zkoss.zul.Filedownload;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Listitem;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Window;

public class DocumentVersionController extends GenericForwardComposer {

	private DocumentVersion documentVersion;
	protected AnnotateDataBinder binder;
	private Long major;
	private Long minor;
	private String description;
	protected Listbox listboxParentDocumentReference;
	protected Listbox listboxChildDocumentReference;
	protected Listbox listboxDocumentVersionFile;
	private DocumentReference selectedParentDocumentReference;
	private DocumentReference selectedChildDocumentReference;
	private DocumentVersionFile selectedDocumentVersionFile;
	private List<DocumentVersionFile> documentVersionFiles;
	private List<DocumentReference> parentDocumentReferences;
	private List<DocumentReference> childDocumentReferences;
	private UserService userService;

	public boolean getIsDisabled() {
		String username = SecurityContextHolder.getContext().getAuthentication().getName();
		User currentUser = this.userService.findByUsername(username);
		
		if (this.documentVersion.getDocument().getLockedBy() != null) {
			if (this.documentVersion.getDocument().getLockedBy().getUsername().equals(currentUser.getUsername())) {
				return false;
			}
		} else if (this.documentVersion.getDocument().getId() == null) {
			return false;
		}
		return true;
	}
	
	public DocumentVersion getDocumentVersion() {
		return documentVersion;
	}

	public void setDocumentVersion(DocumentVersion documentVersion) {
		this.documentVersion = documentVersion;
	}
	
	public DocumentReference getSelectedParentDocumentReference() {
		return selectedParentDocumentReference;
	}

	public void setSelectedParentDocumentReference(
			DocumentReference selectedParentDocumentReference) {
		this.selectedParentDocumentReference = selectedParentDocumentReference;
	}

	public DocumentReference getSelectedChildDocumentReference() {
		return selectedChildDocumentReference;
	}

	public void setSelectedChildDocumentReference(
			DocumentReference selectedChildDocumentReference) {
		this.selectedChildDocumentReference = selectedChildDocumentReference;
	}

	public DocumentVersionFile getSelectedDocumentVersionFile() {
		return selectedDocumentVersionFile;
	}

	public void setSelectedDocumentVersionFile(
			DocumentVersionFile selectedDocumentVersionFile) {
		this.selectedDocumentVersionFile = selectedDocumentVersionFile;
	}
	
	public UserService getUserService() {
		return userService;
	}

	public void setUserService(UserService userService) {
		this.userService = userService;
	}

	@Override
	public void doAfterCompose(Component component) throws Exception {
		super.doAfterCompose(component);
		this.documentVersion = (DocumentVersion) this.execution.getAttribute("documentVersion");
		
		this.documentVersionFiles = new ArrayList<DocumentVersionFile>();
		this.parentDocumentReferences = new ArrayList<DocumentReference>();
		this.childDocumentReferences = new ArrayList<DocumentReference>();
		
		this.saveData();

		component.setAttribute("controller", this);
	}

	public void onClick$menuitemDocumentVersionFileCreate(Event event)
			throws Exception {
		this.documentVersionFileCreate();
	}
	
	public void onClick$menuitemDocumentVersionFileEdit(Event event)
			throws Exception {
		this.documentVersionFileEdit();
	}
	
	public void onClick$menuitemDocumentVersionFileDelete(Event event)
			throws Exception {
		this.documentVersionFileDelete();
	}
	
	public void onClick$toolbarbuttonDocumentVersionFileCreate(Event event)
			throws Exception {
		this.documentVersionFileCreate();
	}
	
	public void onClick$toolbarbuttonDocumentVersionFileEdit(Event event)
			throws Exception {
		this.documentVersionFileEdit();
	}
	
	public void onClick$toolbarbuttonDocumentVersionFileDelete(Event event)
			throws Exception {
		this.documentVersionFileDelete();
	}

	public void onClick$menuitemDocumentVersionParentDocumentReferenceCreate(Event event)
			throws Exception {
		this.parentDocumentReferenceCreate();
	}
	
	public void onClick$menuitemDocumentVersionParentDocumentReferenceEdit(Event event)
			throws Exception {
		this.parentDocumentReferenceEdit();
	}
	
	public void onClick$menuitemDocumentVersionParentDocumentReferenceDelete(Event event)
			throws Exception {
		this.parentDocumentReferenceDelete();
	}
	
	public void onClick$toolbarbuttonParentDocumentReferenceCreate(Event event)
			throws Exception {
		this.parentDocumentReferenceCreate();
	}
	
	public void onClick$toolbarbuttonParentDocumentReferenceEdit(Event event)
			throws Exception {
		this.parentDocumentReferenceEdit();
	}
	
	public void onClick$toolbarbuttonParentDocumentReferenceDelete(Event event)
			throws Exception {
		this.parentDocumentReferenceDelete();
	}

	public void onClick$menuitemDocumentVersionChildDocumentReferenceCreate(Event event)
			throws Exception {
		this.childDocumentReferenceCreate();
	}
	
	public void onClick$menuitemDocumentVersionChildDocumentReferenceEdit(Event event)
			throws Exception {
		this.childDocumentReferenceEdit();
	}
	
	public void onClick$menuitemDocumentVersionChildDocumentReferenceDelete(Event event)
			throws Exception {
		this.childDocumentReferenceDelete();
	}
	
	public void onClick$toolbarbuttonChildDocumentReferenceCreate(Event event)
			throws Exception {
		this.childDocumentReferenceCreate();
	}
	
	public void onClick$toolbarbuttonChildDocumentReferenceEdit(Event event)
			throws Exception {
		this.childDocumentReferenceEdit();
	}
	
	public void onClick$toolbarbuttonChildDocumentReferenceDelete(Event event)
			throws Exception {
		this.childDocumentReferenceDelete();
	}
	
	public void onClick$menuitemDocumentVersionFileSetDefaultFile(Event event)
			throws Exception {
		this.setDefaultFile();
	}
	
	public void onClick$toolbarbuttonDocumentVersionFileSetDefaultFile(Event event)
			throws Exception {
		this.setDefaultFile();
	}
	
	public void onClick$menuitemDocumentVersionFileDownloadFile(Event event)
			throws Exception {
		this.fileDownload();
	}
	
	public void onClick$toolbarbuttonDocumentVersionFileDownloadFile(Event event)
			throws Exception {
		this.fileDownload();
	}
	
	private void documentVersionFileCreate() throws Exception {
		DocumentVersionFile documentVersionFile = new DocumentVersionFile();
		documentVersionFile.setDocumentVersion(this.documentVersion);
		
		this.execution.setAttribute("documentVersionFile", documentVersionFile);

		Window window = (Window) this.execution.createComponents(
				"~./zul/html/documentVersionFile.zul", null, null);
		window.setParent(self);
		window.doModal();

		if (this.execution.getAttribute("result") == "ok") {
			if (!this.documentVersion.getDocumentVersionFiles().isEmpty()) {
				for (DocumentVersionFile uniqueDocumentVersionFile : this.documentVersion.getDocumentVersionFiles()) {
					uniqueDocumentVersionFile.setDefaultFile(null);
				}
			}
			DocumentVersionFile choisenDocumentVersionFile = (DocumentVersionFile) this.execution.getAttribute("documentVersionFile");
			choisenDocumentVersionFile.setDefaultFile("default");
			this.documentVersion.getDocumentVersionFiles().add(choisenDocumentVersionFile);
		}

		this.binder.loadComponent(this.listboxDocumentVersionFile);
	}
	
	private void documentVersionFileEdit() throws Exception {
		if (this.selectedDocumentVersionFile != null) {
			this.execution.setAttribute("documentVersionFile",this.selectedDocumentVersionFile);
			
			Window window = (Window) this.execution.createComponents(
					"~./zul/html/documentVersionFile.zul", null, null);
			window.setParent(self);
			window.doModal();
	
			this.binder.loadComponent(this.listboxDocumentVersionFile);
		}
	}
	
	private void documentVersionFileDelete() throws Exception {
		Set<Listitem> selectedItems = this.listboxDocumentVersionFile.getSelectedItems();

        if (selectedItems.size() > 0) {
            if (Messagebox.YES == Messagebox.show("Delete these records?", "Delete?",
                    Messagebox.YES | Messagebox.NO, Messagebox.QUESTION)) {
                for (Listitem selectedItem : selectedItems) {
                    DocumentVersionFile documentVersionFile = (DocumentVersionFile) selectedItem.getValue();
                    this.documentVersion.getDocumentVersionFiles().remove(documentVersionFile);
                }
                this.selectedDocumentVersionFile = null;
            }
        }

        this.binder.loadAll();
	}

	private void parentDocumentReferenceCreate() throws Exception {
		if (this.documentVersion.getMajor() != null && this.documentVersion.getMinor() != null) {
			DocumentReference documentReference = new DocumentReference();
			documentReference.setChildDocumentVersion(this.documentVersion);
			documentReference.setChildDocument(this.documentVersion.getDocument());
	
			this.execution.setAttribute("documentReference", documentReference);
			this.execution.setAttribute("documentVersionDisabled", "childDocumentVersion");
			this.execution.setAttribute("documentDisabled", "childDocument");
	
			Window window = (Window) this.execution.createComponents(
					"~./zul/html/documentReference.zul", null, null);
			window.setParent(self);
			window.doModal();
			
			if (this.execution.getAttribute("result") == "ok") {
				documentReference = (DocumentReference) this.execution.getAttribute("documentReference");
				
				//TODO: Sprawdzić
				//documentReference.getChildDocument().getParentDocumentReferences().add(documentReference);
				//documentReference.getParentDocument().getChildDocumentReferences().add(documentReference);
				this.documentVersion.getParentDocumentReferences().add(documentReference);
				
//				if (documentReference.getParentDocument() == this.documentVersion.getDocument()) {
//					this.documentVersion.getDocument().getParentDocumentReferences().add(documentReference);
//				}
//				if (documentReference.getParentDocument() == this.documentVersion.getDocument()) {
//					this.documentVersion.getDocument().getChildDocumentReferences().add(documentReference);
//				}
//				if (documentReference.getChildDocument() == this.documentVersion.getDocument()) {
//					this.documentVersion.getDocument().getChildDocumentReferences().add(documentReference);
//				}
//				if (documentReference.getChildDocument() == this.documentVersion.getDocument()) {
//					this.documentVersion.getDocument().getParentDocumentReferences().add(documentReference);
//				}
				if (documentReference.getParentDocumentVersion() == this.documentVersion) {
					this.documentVersion.getParentDocumentReferences().add(documentReference);
				}
			}

			this.binder.loadAll();
			
		} else {
			Messagebox.show("You must enter 'Major' and 'Minor'.");
		}
	}
	
	private void parentDocumentReferenceEdit() throws Exception {
		if (this.selectedParentDocumentReference != null) {
			this.execution.setAttribute("documentReference",this.selectedParentDocumentReference);
			this.execution.setAttribute("documentVersionDisabled", "childDocumentVersion");
			this.execution.setAttribute("documentDisabled", "childDocument");
		
			Window window = (Window) this.execution.createComponents(
					"~./zul/html/documentReference.zul", null, null);
			window.setParent(self);
			window.doModal();
	
			this.binder.loadComponent(this.listboxParentDocumentReference);
		}
	}
	
	private void parentDocumentReferenceDelete() throws Exception {
		Set<Listitem> selectedItems = this.listboxParentDocumentReference.getSelectedItems();

        if (selectedItems.size() > 0) {
            if (Messagebox.YES == Messagebox.show("Delete these records?", "Delete?",
                    Messagebox.YES | Messagebox.NO, Messagebox.QUESTION)) {
                for (Listitem selectedItem : selectedItems) {
                    DocumentReference documentReference = (DocumentReference) selectedItem.getValue();
                    this.documentVersion.getDocument().getParentDocumentReferences().remove(documentReference);
                    this.documentVersion.getDocument().getChildDocumentReferences().remove(documentReference);
                    
	                for (DocumentVersion documentVersion : this.documentVersion.getDocument().getDocumentVersions()) {
	                	documentVersion.getParentDocumentReferences().remove(documentReference);
	                	documentVersion.getChildDocumentReferences().remove(documentReference);
	                }     
                }
                this.selectedParentDocumentReference = null;
            }
        }

        this.binder.loadAll();
	}

	private void childDocumentReferenceCreate() throws Exception {
		if (this.documentVersion.getMajor() != null && this.documentVersion.getMinor() != null) {
			DocumentReference documentReference = new DocumentReference();
			documentReference.setParentDocumentVersion(this.documentVersion);
			documentReference.setParentDocument(this.documentVersion.getDocument());
	
			this.execution.setAttribute("documentReference", documentReference);
			this.execution.setAttribute("documentVersionDisabled", "parentDocumentVersion");
			this.execution.setAttribute("documentDisabled", "parentDocument");
	
			Window window = (Window) this.execution.createComponents(
					"~./zul/html/documentReference.zul", null, null);
			window.setParent(self);
			window.doModal();
			
			if (this.execution.getAttribute("result") == "ok") {
				this.documentVersion.getChildDocumentReferences().add(
						(DocumentReference) this.execution
								.getAttribute("documentReference"));
			}

			this.binder.loadComponent(this.listboxChildDocumentReference);
			
		} else {
			Messagebox.show("You must enter 'Major' and 'Minor'.");
		}
	}
	
	private void childDocumentReferenceEdit() throws Exception {
		if (this.selectedChildDocumentReference != null) {
			this.execution.setAttribute("documentReference",this.selectedChildDocumentReference);
			this.execution.setAttribute("documentVersionDisabled", "parentDocumentVersion");
			this.execution.setAttribute("documentDisabled", "parentDocument");
		
			Window window = (Window) this.execution.createComponents(
					"~./zul/html/documentReference.zul", null, null);
			window.setParent(self);
			window.doModal();
	
			this.binder.loadComponent(this.listboxChildDocumentReference);
		}
	}
	
	private void childDocumentReferenceDelete() throws Exception {
		Set<Listitem> selectedItems = this.listboxChildDocumentReference.getSelectedItems();

        if (selectedItems.size() > 0) {
            if (Messagebox.YES == Messagebox.show("Delete these records?", "Delete?",
                    Messagebox.YES | Messagebox.NO, Messagebox.QUESTION)) {
                for (Listitem selectedItem : selectedItems) {
                    DocumentReference documentReference = (DocumentReference) selectedItem.getValue();
                    this.documentVersion.getDocument().getParentDocumentReferences().remove(documentReference);
                    this.documentVersion.getDocument().getChildDocumentReferences().remove(documentReference);
                    
	                for (DocumentVersion documentVersion : this.documentVersion.getDocument().getDocumentVersions()) {
	                	documentVersion.getParentDocumentReferences().remove(documentReference);
	                	documentVersion.getChildDocumentReferences().remove(documentReference);
	                }     
                }
                this.selectedChildDocumentReference = null;
            }
        }
        
        this.binder.loadAll();
	}

	public void onClick$buttonOk(Event event) throws Exception {
		if (this.documentVersion.getMajor() != null && this.documentVersion.getMinor() != null) {
			boolean isDefaultFile = false;
			if (!this.documentVersion.getDocumentVersionFiles().isEmpty()) {
				for (DocumentVersionFile documentVersionFile : this.documentVersion.getDocumentVersionFiles()) {
					if (documentVersionFile.getDefaultFile() != null) {
						isDefaultFile = true;
					}
				}
			}
			if (isDefaultFile == true) {
				this.execution.setAttribute("documentVersion", this.documentVersion);
				this.execution.setAttribute("result", "ok");
				this.self.detach();
			} else {
				Messagebox.show("You must select a 'Default File'.");
			}
		} else {
			Messagebox.show("You must enter 'Major' and 'Minor'.");
		}
	}

	public void onClick$buttonCancel(Event event) throws Exception {
		this.restoreData();

		this.execution.setAttribute("documentVersion", null);
		this.execution.setAttribute("result", "cancel");
		this.self.detach();
	}

	private void saveData() {
		for (DocumentVersionFile documentVersionFile : this.documentVersion.getDocumentVersionFiles()) {
			DocumentVersionFile clonnedDocumentVersionFile = new DocumentVersionFile();
			clonnedDocumentVersionFile.setId(documentVersionFile.getId());
			clonnedDocumentVersionFile.setCultureInfo(documentVersionFile.getCultureInfo());
			clonnedDocumentVersionFile.setFile(documentVersionFile.getFile());
			clonnedDocumentVersionFile.setSoftwareVersion(documentVersionFile.getSoftwareVersion());
			clonnedDocumentVersionFile.setDefaultFile(documentVersionFile.getDefaultFile());
			clonnedDocumentVersionFile.setDocumentVersion(documentVersionFile.getDocumentVersion());
			this.documentVersionFiles.add(clonnedDocumentVersionFile);
		}
		
		for (DocumentReference parentDocumentReference : this.documentVersion.getParentDocumentReferences()) {
			DocumentReference clonnedParentDocumentReference = new DocumentReference();
			clonnedParentDocumentReference.setId(parentDocumentReference.getId());
			clonnedParentDocumentReference.setDocumentReferenceType(parentDocumentReference.getDocumentReferenceType());
			clonnedParentDocumentReference.setChildDocument(parentDocumentReference.getChildDocument());
			clonnedParentDocumentReference.setChildDocumentVersion(parentDocumentReference.getChildDocumentVersion());
			clonnedParentDocumentReference.setParentDocument(parentDocumentReference.getParentDocument());
			clonnedParentDocumentReference.setParentDocumentVersion(parentDocumentReference.getParentDocumentVersion());
			this.parentDocumentReferences.add(clonnedParentDocumentReference);
		}
		
		for (DocumentReference childDocumentReference : this.documentVersion.getChildDocumentReferences()) {
			DocumentReference clonnedChildDocumentReference = new DocumentReference();
			clonnedChildDocumentReference.setId(childDocumentReference.getId());
			clonnedChildDocumentReference.setDocumentReferenceType(childDocumentReference.getDocumentReferenceType());
			clonnedChildDocumentReference.setChildDocument(childDocumentReference.getChildDocument());
			clonnedChildDocumentReference.setChildDocumentVersion(childDocumentReference.getChildDocumentVersion());
			clonnedChildDocumentReference.setParentDocument(childDocumentReference.getParentDocument());
			clonnedChildDocumentReference.setParentDocumentVersion(childDocumentReference.getParentDocumentVersion());
			this.childDocumentReferences.add(clonnedChildDocumentReference);
		}
		
		this.major = this.documentVersion.getMajor();
		this.minor = this.documentVersion.getMinor();
		this.description = this.documentVersion.getDescription();
	}

	private void restoreData() {
		this.documentVersion.getDocumentVersionFiles().clear();
		for (DocumentVersionFile documentVersionFile : this.documentVersionFiles) {
			this.documentVersion.getDocumentVersionFiles().add(documentVersionFile);
		}
		
		this.documentVersion.getParentDocumentReferences().clear();
		for (DocumentReference parentDocumentReference : this.parentDocumentReferences) {
			this.documentVersion.getParentDocumentReferences().add(parentDocumentReference);
		}
		
		this.documentVersion.getChildDocumentReferences().clear();
		for (DocumentReference childDocumentReference : this.childDocumentReferences) {
			this.documentVersion.getChildDocumentReferences().add(childDocumentReference);
		}
		
		this.documentVersion.setMajor(this.major);
		this.documentVersion.setMinor(this.minor);
		this.documentVersion.setDescription(this.description);
	}
	
	private void setDefaultFile() throws Exception {
		if (this.selectedDocumentVersionFile != null) {
			for (DocumentVersionFile documentVersionFile : this.documentVersion.getDocumentVersionFiles()) {
				documentVersionFile.setDefaultFile(null);
			}
			this.selectedDocumentVersionFile.setDefaultFile("default");
			this.binder.loadComponent(this.listboxDocumentVersionFile);
        } else {
        	Messagebox.show("Please select at least one item!");
        }
    }
	
	private void fileDownload() throws Exception {
    	if (this.selectedDocumentVersionFile != null) {
    		if (this.selectedDocumentVersionFile.getFile() != null) {
    			Filedownload.save(
    				this.selectedDocumentVersionFile.getFile().getContent(), 
    				this.selectedDocumentVersionFile.getFile().getContentType(), 
    				this.selectedDocumentVersionFile.getFile().getName());
    		} else {
            	Messagebox.show("There is no file to download!");
            }
        } else {
        	Messagebox.show("Please select at least one item!");
        }
    }
	
}
